goog.provide('mitel.calendar_gadget');
goog.require('mitel.deployment');
goog.require('goog.structs.Map');
goog.require('goog.Uri.QueryData');
goog.require('mitel.socket');

var prefs = new _IG_Prefs();

var EMAIL = '';

/** @const */
var GOOGLE_CALENDAR = google.calendar;

/** @const */
var GOOGLE_CALENDAR_READ = GOOGLE_CALENDAR.read;

(function () {
    $.fn.identify = function (prefix) {
        var i = 0;
        return this.each(function () {
            if ($(this).prop('id'))
                return;
            do {
                i++;
                var id = prefix + '_' + i;
            } while ($('#' + id).length > 0);
            $(this).prop('id', id);
        });
    };

    var body = $('body').first();

    var contentPane = $('<div/>').hide();

    var enableCollabBox = $('<input/>', {
        value: 'Collaboration',
        type: 'checkbox'
    });

    var enableCollabLabel = $('<label/>', {
        'for': enableCollabBox.identify('test'),
        'text': 'Collaboration'
    });
    contentPane.append(enableCollabBox);
    contentPane.append(enableCollabLabel);

    var infoPane = $('<div/>', {
        text: 'Select a calendar event.'
    }).addClass('infoPane');

    var permission = $('<div/>').hide();

    var permButton = $('<button/>', {
        text: 'Permissions'
    });
    permission.append(permButton);

    var out = $('<div/>');

    /**
     * Should the icon apply to all instances in a recurring series.
     * @type {boolean}
     * @private
     */
    var allInstances_ = true;

    /**
     * The icon that we are in the process of adding. null if we are removing it.
     * @type {string?}
     * @private
     */
    var iconToAdd_ = null;

    /**
     * The collaboration session ID that we are in the process of adding. null if
     * we are removing it.
     * @type {string?}
     * @private
     */
    var collabSession_ = null;

    var COLLAB_KEY = 'collabSession';
    var LOADING_TEXT = 'Saving...';
    var miniMsg = new gadgets.MiniMessage('main');
    var msg = null;
    var currentTitle = 'Mitel';

    /**
     * The event currently displayed on the screen. null if there is no event.
     * @type {google.gdata.calendar.CalendarEventEntry}
     * @private
     */
    var currentEvent_ = null;
    var gdataService_ = null;
    var prefs_ = null;

    gadgets.window.adjustHeight();
    initGData();

    GOOGLE_CALENDAR.getPreferences(function (data) {
        prefs_ = data;
    });
    function getEmail() {
        var login = null;
        if ('viewer' in prefs_) {
            login = prefs_.viewer;
        }
        return login;
    }

    function readCalendarData() {
        var gdataId;
        if (allInstances_) {
            gdataId = GOOGLE_CALENDAR_READ.getRecurringGDataId(currentEvent_);
        } else {
            gdataId = GOOGLE_CALENDAR_READ.getGDataId(currentEvent_);
        }
        var gdataCallback = makeCallback(readEvent, arguments.callee);
        gdataService_.getCalendarEventEntry(gdataId, gdataCallback, function (err) {
          alert(err);
        });
    }

    /**
     * @param {google.gdata.calendar.CalendarEventEntry} e Calendar Event.
     */
    function subscribeEventsCallback(e) {
        var html = '';
        if (!e) {
            infoPane.show();
            if (currentTitle == 'Mitel') {
                return;
            }
            // No new event, leave the existing event up.
            contentPane.hide();
            gadgets.window.adjustHeight();
            return;
        }
        if (!e.id) {
            // Newly created event, show an error message.
            updateTitle('Mitel');
            infoPane.show();
            contentPane.hide();
            return;
        }

        // NOTE - For now, only works on existing event on the organizer's calendar.
        if (e.accessLevel == 'owner' || e.accessLevel == 'editor' || e.accessLevel == 'root') {
            currentEvent_ = e;

            // If (it's recurring) then
            //   A) apply to entire series by default
            //   B) add a checkbox to let the user specialize the series
            // }
            if (GOOGLE_CALENDAR_READ.isRecurring(e)) {
                allInstances_ = true;
                html += '<div><input id=recur onclick="allInstances_=!allInstances_"' + ' type=checkbox checked><label for=recur> ' + '__MSG_Add_All_In_Series__' + '</label></div>';
            } else {
                allInstances_ = false;
            }

            updateTitle(currentEvent_.title);
            setTimeout(readCalendarData, 1);
        } else {
            // The event is on someone else's calendar.
            updateTitle('Mitel');
            infoPane.show();
            currentEvent_ = null;
        }

    }

    /**
     * The cached preference object.
     */
    var _prefs = null;

    /**
     * Get the translated message for the ID.
     * @param {string} id The id of the message.
     * @return {string} The resulting string.
     */
    function getMsg(id) {
        if (!_prefs) {
            _prefs = new gadgets.Prefs();
        }
        return _prefs.getMsg(id);
    }

    /**
     * Get the date as a string (YYYY-MM-DD HH:MM) from the event date object.
     * @param {Date} eventDate the event's date
     * @return {string} The resulting date string.
     */
    function getDateFromEvent(eventDate) {
      return eventDate['year'] + '-' +
              ('0' + eventDate['month']).slice(-2)  + '-' +
              ('0' + eventDate['date']).slice(-2)   + ' ' +
              ('0' + eventDate['hour']).slice(-2)   + ':' +
              ('0' + eventDate['minute']).slice(-2);
    }

    /**
     * Add an icon.
     */
    function enableCollab() {
        var startDate = currentEvent_.startTime.year + '-' + currentEvent_.startTime.year;

        var postMap = new goog.structs.Map({
            'userId': currentEvent_.creator.email,
            'topic': currentEvent_.title,
            'startTime': getDateFromEvent(currentEvent_.startTime),
            'endTime': getDateFromEvent(currentEvent_.endTime)
        });
        var postData = goog.Uri.QueryData.createFromMap(postMap);

        var op = null;
        var callback = null;
        if (enableCollabBox.prop('checked')) {
            op = "create";
            callback = function (response) {
                collabSession_ = response.currentTarget.getResponseJson();
                updateHelper();
            };
        } else {
            op = "delete";
            callback = function (response) {
                  collabSession_ = null;
                  updateHelper();
             };
        };

        var params = {};
        var url = mitel.deployment.backend_server + "mslrest/google/v1/mca/conference?op=" + op + "&ts=" + new Date().getTime();
        params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
        params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.OAUTH;
        params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "google";
        params[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always";
        params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
        params[gadgets.io.RequestParameters.POST_DATA]= postData.toString();


        gadgets.io.makeRequest(url, function (response) {
            if (response.oauthApprovalUrl) {
              // Create the popup handler. The onOpen function is called when the user
              // opens the popup window. The onClose function is called when the popup
              // window is closed.
              var popup = shindig.oauth.popup({
                destination: response.oauthApprovalUrl,
                windowOptions: null,
                onOpen: function() { showOneSection('waiting'); },
                onClose: function() { fetchData(); }
              });
              // Use the popup handler to attach onclick handlers to UI elements.  The
              // createOpenerOnClick() function returns an onclick handler to open the
              // popup window.  The createApprovedOnClick function returns an onclick
              // handler that will close the popup window and attempt to fetch the user's
              // data again.
              /*var personalize = document.getElementById('personalize');
              personalize.onclick = popup.createOpenerOnClick();
              var approvaldone = document.getElementById('approvaldone');
              approvaldone.onclick = popup.createApprovedOnClick();
              showOneSection('approval');
              */
            } else if (response.data) {
                //showOneSection('main');
                console.error(response.data);
            } else {
                // The response.oauthError and response.oauthErrorText values may help debug
                // problems with your gadget.
                /*var main = document.getElementById('main');
                var err = document.createTextNode('OAuth error: ' +
                  response.oauthError + ': ' + response.oauthErrorText);
                main.appendChild(err);
                showOneSection('main');*/
                console.error(response);
            }
          }, params);

        /*goog.net.XhrIo.send(mitel.deployment.backend_server + 'v1/mca/conference/?op=' + op + "&ts=" + new Date().getTime(),
            callback, 'POST', postData.toString());*/
    }

    function updateHelper() {
        msg = miniMsg.createStaticMessage(LOADING_TEXT);
        gadgets.window.adjustHeight();
        contentPane.toggle();
        var gdataId;
        if (allInstances_) {
            gdataId = GOOGLE_CALENDAR_READ.getRecurringGDataId(currentEvent_);
        } else {
            gdataId = GOOGLE_CALENDAR_READ.getGDataId(currentEvent_);
        }

        if (gdataId == '' || !gdataId) {
            updateEvent(currentEvent_);
            return;
        }

        var gdataCallback = makeCallback(updateEvent, arguments.callee);
        gdataService_.getCalendarEventEntry(gdataId, gdataCallback);
    }

    function getProp(key, extendedProps) {
        for (var i = 0; i < extendedProps.length; ++i) {
            if (extendedProps[i].getName() == key) {
                return extendedProps[i];
            }
        }
        return null;
    }

    /**
     * Receives the event, and proceeds to update the collab ID and icon.
     * @param {gdata} results GData Calendar Event.
     * @return {boolean} Whether or not events were found.
     */
    function updateEvent(results) {
        if (!results) {
            return false;
        }
        var calendarEntry = results.entry;

        var extendedProps = calendarEntry.getExtendedProperties();
        var content = null;
        if (null != collabSession_) {
            for (var i = 0; i < collabSession_.length; ++i) {
                collabProp = new google.gdata.ExtendedProperty();
                collabProp.setName(collabSession_[i][0]);
                collabProp.setValue(collabSession_[i][1]);
                calendarEntry.addExtendedProperty(collabProp);
            }
            var wc = new google.gdata.calendar.WebContent();
            wc.setUrl(mitel.deployment.host + 'calendar_gadget.xml');
            wc.setDisplay(google.gdata.calendar.WebContent.DISPLAY_CHIP);
            wc.setHeight(140);
            wc.setWidth(300);

            var collabSession = new google.gdata.calendar.WebContentGadgetPref();
            collabSession.setName('collabSession');
            collabSession.setValue(collabSession_[4][1]);  //FIXME ..lazyness at 1 am
            wc.addGadgetPref(collabSession);

            var eventLink = new google.gdata.calendar.WebContentGadgetPref();
            eventLink.setName('eventLink');
            eventLink.setValue(calendarEntry.getHtmlLink()['href']);
            wc.addGadgetPref(eventLink);

            var t = 'Mitel Collaboration';
            var mime = 'application/x-google-gadgets+xml';
            var icon = mitel.deployment.host + 'images/icon.png';
            var wcLink = google.gdata.calendar.CalendarLink.create(wc, icon, t, mime);
            calendarEntry.setWebContentLink(wcLink);

        } else {
            //Should be smarter here and not wipe the props in case
            //some other active gadget is in play
            calendarEntry.setExtendedProperties(null);
            calendarEntry.removeWebContent();
        }

        calendarEntry.updateEntry(successCallback);

        return true;
    }

    /**
     * @param {google.calendar.CalendarResult} results Results.
     */
    function readEvent(results) {
        if (!results) {
            return false;
        }
        infoPane.hide();

        var extendedProps = results.entry.getExtendedProperties();
        var collabProp = getCollabSession('confID', extendedProps);
        var collabEnabled = collabProp && collabProp.getValue() != null && collabProp.getValue() != '';
        enableCollabBox.prop('checked', collabEnabled);
        contentPane.show();

        return true;
    }

    function getCollabSession(key, extendedProps) {
        for (var i = 0; i < extendedProps.length; ++i) {
            if (extendedProps[i].getName() == key) {
                return extendedProps[i];
            }
        }
        return null;
    }


    /**
     * Callback function from the update.
     */
    function successCallback() {
        contentPane.toggle();
        miniMsg.dismissMessage(msg);
        gadgets.window.adjustHeight();
        updateTitle(currentEvent_.title);
        GOOGLE_CALENDAR.refreshEvents();
    }

    function updateTitle(title) {
        currentTitle = title;
        if (null == currentTitle || currentTitle == "") {
            currentTitle = "Collaboration session";
        }
        gadgets.window.setTitle(currentTitle);
    }

    ///////////////////////////////////////////////////////////////////////////
    // GDATA Helper Functions.

    function initGData() {
        if (!gdataService_) {
            gdataService_ = new google.gdata.calendar.CalendarService('Mitel');
            gdataService_.useOAuth('google');
        }
    }

    var popup_;

    /**
     * HACK to pick the right account and speed up the process
     * @return {string} URL fragment to append to OAuth request.
     */
    function getOAuthUrlSuffix() {
        var user = 'default';
        var params = gadgets.util.getUrlParameters();
        if (params && params.parent) {
            var HOSTED = '/hosted/';
            var hosted = params.parent.indexOf(HOSTED);
            if (hosted != -1) {
                user = params.parent.substr(hosted + HOSTED.length);
            }
            return '&hd=' + escape(user);
        }
        return '';
    }

    /**
     * @param {Function(response):boolean} func A function. It receives a
     *   response from the server. If it is HAPPY with the results, return true.
     *   Otherwise return false.
     * @param {Function} originalFunc The original function.
     * @return {Function} a wrapped function for the callback.
     */
    function makeCallback(func, originalFunc) {

        /**
         * @param {google.calendar.CalendarResult|google.oauth.OAuthApproval} response API request response.
         */
        return function (response) {
            if (response && response.oauthApprovalUrl) {
                permButton.click(function () {
                    popup_.createOpenerOnClick()();
                });

                popup_ = new gadgets.oauth.Popup(response.oauthApprovalUrl + getOAuthUrlSuffix(), 'height=600,width=800', function () {
                    permission.hide();
                }, originalFunc);
                permission.show();
            } else if (!func(response)) {
            }
            gadgets.window.adjustHeight();
        };
    }

    function toggleDisabled(el) {
        try {
            el.disabled = el.disabled ? false : true;
        } catch (E) {
        }
        if (el && el.childNodes && el.childNodes.length > 0) {
            for (var x = 0; x < el.childNodes.length; x++) {
                toggleDisabled(el.childNodes[x]);
            }
        }
    }

    function getParentWindowParameterByName(name) {
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
        var regexS = "[\\?&]" + name + "=([^&#]*)";
        var regex = new RegExp(regexS);
        var results = regex.exec(window.parent.location.search);
        if (results == null)
            return false;
        else
            return decodeURIComponent(results[1].replace(/\+/g, " "));
    }

    var ready = function (email) {
        //alert('Logged in user\'s email address is: ' + email);
        EMAIL = email;
        var socket = mitel.socket.connect(mitel.deployment.socket_server);

        socket.on('connect', function () {
            socket.emit('nickname', {
                'nickname': email
            });
        });

        permission.hide();

        var prefs = new gadgets.Prefs();
        var collabSession = prefs.getString('collabSession');
        var collabUrl = "#";
        if (!collabSession) {
            body.append(infoPane);

            enableCollabBox.click(function () {
                enableCollab();
            });

            GOOGLE_CALENDAR_READ.subscribeToEvents(subscribeEventsCallback);

            if (getParentWindowParameterByName('eid')) {
                var eid = getParentWindowParameterByName('eid');
                var decoded = GOOGLE_CALENDAR_READ.decode64(eid).split(' ');
                var eventURL = "https://www.google.com/calendar/feeds/" + decoded[1] + "/private/full/" + decoded[0];
                gdataService_.getCalendarEventEntry(eventURL, function (e) {
                    window['curevent'] = e;
                    window['curentry'] = e.entry;
                    currentEvent_ = e;
                    readEvent(e);
                });
            }
        } else {
            var collabLink = $('<a/>', {
                href: collabSession,
                text: collabSession,
                target: '_new'
            });
            body.append(collabLink);
        }
    };
    
    var showAuth = function (response) {
        var popup = new gadgets.oauth.Popup(response.oauthApprovalUrl, "height=500,width=500", function () {

        }, function () {
            boot();
        });

        permission.show();
        permButton.click(popup.createOpenerOnClick());
    };
    
    var boot = function () {
        var params = {};
        url = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
        params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.JSON;
        params[gadgets.io.RequestParameters.AUTHORIZATION] = gadgets.io.AuthorizationType.OAUTH;
        params[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "google";
        params[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always";
        params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.GET;

        gadgets.io.makeRequest(url, function (response) {
            if (response.oauthApprovalUrl) {
                showAuth(response);
            } else {
                ready(response.data['email']);
            }
        }, params);

    };

    $(document).ready(function () {
        $('head').append('<link rel="stylesheet" ' + 'href="' + mitel.deployment.host + 'css/calendar.css" ' + 'type="text/css" />');

        var logo = $('<img/>', {
            src: mitel.deployment.host + 'images/logo.png'
        }).addClass('logo');

        body.append(logo);

        body.append(contentPane);
        body.append(permission);
        body.append(out);

        var prefs = new gadgets.Prefs();
        var collabSession = prefs.getString('collabSession');

        if (!collabSession) {
            boot();
        } else {
            var collabLink = $('<a/>', {href: collabSession, text: collabSession, target: '_new'});
            var editLink = $('<button/>', {text: 'Edit this Calendar Event'});
            editLink.click(function (event) {
                event.stopPropagation();
                var eventLink = prefs.getString('eventLink');
                window.open(eventLink);
            });
            body.append(collabLink);
            body.append($('<br />'));
            body.append($('<br />'));
            body.append(editLink);
        }
    });
})();
